package cn.springcloud.book.config;


import cn.springcloud.book.token.JwtTokenEnhancer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;

@Configuration
@EnableAuthorizationServer
public class OAuthConfiguration extends AuthorizationServerConfigurerAdapter {
	
	@Autowired
	private AuthenticationManager authenticationManager;

	@Resource
    private DataSource dataSource;


	@Value("${security.oauth2.resource.jwt.key-value}")
    private String jwtkey;
	@Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients
                // TODO 使用数据库方式声明的client，使用@EnableOAuth2Sso，访问zuul时无法完成自动验证。原因未知！
                // TODO zuul自动完成验证跳转，使用的是授权码模式，但是为什么不需要在zuul和认证服务器指定redirect_uri，两边却能把redirect_uri对上。
               //.jdbc(dataSource);
        .inMemory()
        .withClient("webApp")
        .secret("123456")
                //scope可以自定义，就是在认证的时候，需要对得上。
        .scopes("WRIGTH", "read")
                //autoApprove(true)这个就是在请求授权码的时候自动批准，这样就是不会跳出窗口询问用户是否同意授权；
                .autoApprove(true)
                //具体的权限，需要user的权限对应
                .authorities("WRIGTH_READ", "WRIGTH_WRITE")
                //认证方式
        .authorizedGrantTypes("implicit", "refresh_token", "password", "authorization_code");
    }

	@Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

	    //把增强器jwtTokenEnhancer添加入增强器集合enhancerList，然后把增强器集合enhancerList设置到增强器链enhancerChain
	    TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
	    List<TokenEnhancer> enhancerList = new ArrayList<>();
	    enhancerList.add(jwtTokenEnhancer());
	    enhancerList.add(jwtTokenConverter());
	    enhancerChain.setTokenEnhancers(enhancerList);



        endpoints
                //使用jwtToken
                .tokenStore(jwtTokenStore())
                //token转换器
                .accessTokenConverter(jwtTokenConverter())
                //JWTToken增强器
                .tokenEnhancer(enhancerChain)
                .authenticationManager(authenticationManager)
                // TODO 这里声明userDetailsService起到什么作用？
        //.userDetailsService(new MyUserDetaoilService())
        ;
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
                .allowFormAuthenticationForClients()//允许使用表单验证
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("isAuthenticated()"); //allow check token
    }

    //声明一个JWTTokenStore
    @Bean
    public TokenStore jwtTokenStore() {
        return new JwtTokenStore(jwtTokenConverter());
    }

    //声明有个令牌增强器
    @Bean
    public TokenEnhancer jwtTokenEnhancer(){
        return new JwtTokenEnhancer();
    }
    //声明一个令牌转换器
    @Bean
    protected JwtAccessTokenConverter jwtTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(jwtkey);
        return converter;
    }
}
